package net.cloudcodex.server;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.cloudcodex.server.data.AdvancedDAO;
import net.cloudcodex.server.data.DAO;
import net.cloudcodex.server.data.Data;
import net.cloudcodex.server.data.Data.Campaign;
import net.cloudcodex.server.data.Data.CharacterNote;
import net.cloudcodex.server.data.Data.Message;
import net.cloudcodex.server.data.Data.Notification;
import net.cloudcodex.server.data.Data.Scene;
import net.cloudcodex.server.data.campaign.msg.SceneSDO;
import net.cloudcodex.server.service.CampaignService;
import net.cloudcodex.server.service.HomeService;
import net.cloudcodex.server.service.MessageService;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Transaction;

/**
 * Runs when the app starts to install test data in DB.
 * 
 * @author Thomas
 */
public class InitServletImpl extends HttpServlet {

	private HomeService homeService;

	private CampaignService campaignService;

	private MessageService messageService;

	private List<Notification> notifications = new ArrayList<Notification>();

	protected final Logger logger = Logger.getLogger(getClass().getName());
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		
		final DatastoreService datastore = 
			DatastoreServiceFactory.getDatastoreService();

		final AdvancedDAO dao = new AdvancedDAO(datastore);

		homeService = new HomeService(datastore);
		campaignService = new CampaignService(datastore);
		messageService = new MessageService(datastore);

		
		// remove all data from datastore
		logger.info("delete datastore");
		for(Entity entity : datastore.prepare(new Query().setKeysOnly()).asIterable()) {
			datastore.delete(entity.getKey());
		}
		
		// init
		logger.info("init datastore");
		init(datastore, dao);

		logger.info("datastore set up");
	}
	
	private Data.User createUser(DAO dao, String email, String nickname) {
		
		final Data.User user = homeService.createUser(null, email, nickname);

		createNotification(dao, "Welcome on CloudCodex " + nickname 
				+ "! You've been created on " + new Date(), user.getKey());

		return user;
	}
	
	private Data.CharacterNote createNote(DAO dao, Data.Character on, Data.Character by, String text) {
	
		final CharacterNote note = new CharacterNote(on);
		note.setAuthor(by);
		note.setContent(text);
		dao.save(null, note);
		return note;
	}
	
	private void createNotification(DAO dao, String message, Key to) {
		final Notification notification = new Notification();
		notification.setMessage(message);
		notification.setTo(to);
		notifications.add(notification);
	}
	
	private Data.Character createCharacter(DAO dao, Campaign campaign, String name, Data.User owner) {
		return createCharacter(dao, campaign, name, owner, null, null);
	}

	private Data.Character createCharacter(DAO dao, 
			Campaign campaign, String name, Data.User owner, String icon, String description) {

		final Data.Character character = campaignService.createCharacter(null, campaign, name, owner, icon, description);
		
		if(owner != null) {
			createNotification(dao, "Hello " + name + ", " + character.getDate() 
					+ " is a good day to be born", character.getKey());
		}
		
		return character;
	}
	
	/**
	 * Init a DB with some users and campaign.
	 */
	private void init(DatastoreService datastore, AdvancedDAO dao) {
		
		final Context context = new Context(null);
		
		notifications.clear();
		createNotification(dao, "This is a general message, everyone see it !", null);
		
		{
			final Data.User thomas = createUser(dao, "thomas.levavasseur@gmail.com", "Thomas");
			final Data.User arnaud = createUser(dao, "arnaud@example.com", "Arnaud");
			final Data.User daniel = createUser(dao, "daniel@example.com", "Daniel");
			final Data.User xavier = createUser(dao, "xavier@example.com", "Xavier");
			final Data.User romain = createUser(dao, "krazlafas@gmail.com", "Romain");
			
			{
				final Transaction tx = datastore.beginTransaction();
				try {
					final Campaign campaign = campaignService.createCampaign(null, "Thomas's Campaign", "Some game", "Some desc", null, thomas);
					
					// Create a generic notification for all characters of the notification.
					createNotification(dao, "Please make OFF session to define your character", campaign.getKey());
					
					
					final Data.Character ulrich = createCharacter(dao, campaign, "Ulrich", xavier);
					final Data.Character olukun = createCharacter(dao, campaign, "Olukun", arnaud);
					final Data.Character hektor = createCharacter(dao, campaign, "Hektor", daniel);
					final Data.Character inigo = createCharacter(dao, campaign, "Inigo", romain);
					createNote(dao, ulrich, inigo, "I think he wants to kill me !!!");
					
					final Data.Character deBloni = createCharacter(dao, campaign, "Victor de Bloni", null);
					createNote(dao, deBloni, ulrich, "Met at Shallya's orphanage");
					createNote(dao, deBloni, hektor, "He hides something ...");
					
					final Data.Character guardChief = createCharacter(dao, campaign, "Otto Meuler", null);
					guardChief.setDescription("Faussenburg's Guard Chief");
					dao.save(null, guardChief);

					final Data.Character mayor = createCharacter(dao, campaign, "Herman Storn", null);
					mayor.setDescription("Faussenburg's Mayor");
					dao.save(null, mayor);
					
					// commit here because cannot read items ...
					tx.commit();

					/*
					 * Init some scenes and messages.
					 */
					Scene scene = messageService.startScene(context, "You're talking to the Guard chief", ulrich, inigo, guardChief);
					scene.setAlias(guardChief.getKey().getId() + "", "Global Alias for Guard Chief");
					scene.setAlias(ulrich.getKey().getId() + "", "Global Alias for Ulrich");
					scene.setAlias(ulrich.getKey().getId() + "-" + inigo.getKey().getId(), "My friend");
					dao.save(context, scene);
					messageService.postSpeech(context, null, ulrich, "Have you seen the mayor ?");
					messageService.postSpeech(context, null, ulrich, "Guy, I'm talking to you !");
					messageService.postSpeech(context, scene.getKey(), guardChief, "No, Not the last days. I'm worried.");
					messageService.postSpeech(context, null, inigo, "I'm sure he's gone with the town gold !");
					messageService.postSpeech(context, scene.getKey(), guardChief, "I'm going right now to check the bank !");
					scene = messageService.startScene(context, "Guard chief is gone, you're alone in the street", ulrich, inigo);
					messageService.postSpeech(context, null, inigo, "OK, wat a stupid guy ...");
					messageService.postSpeech(context, null, ulrich, "Yes, we can now deliver our friend from the jail.");
					messageService.postSpeech(context, null, inigo, "Let's go ! I'm going to search Hektor");
					scene = messageService.startScene(context, "Hektor, Inigo is coming to you at the inn", hektor, inigo);
					messageService.postSpeech(context, null, inigo, "You ! Come with me !");
					messageService.postSpeech(context, null, hektor, "Huh ?!? OK ...");
					
					// now ulrich scene
					messageService.postOFF(context, null, ulrich.getKey(), null, "Is it to late to go to the market ?");
					messageService.postOFF(context, null, null, ulrich.getKey(), "No, you can.");
					messageService.postOFF(context, null, ulrich.getKey(), null, "So I go to the market");
					messageService.postOFF(context, null, null, ulrich.getKey(), "When arriving to market, you see Olukun.");
					messageService.postOFF(context, null, ulrich.getKey(), null, "I go talk to him");
					scene = messageService.startScene(context, "Olukun, Ulrich is here.", ulrich, olukun);
					messageService.postSpeech(context, null, olukun, "Hey ! How do you do ?");
					
					// ...
					scene = messageService.startScene(context, "Everybody is here ...", ulrich, olukun, hektor, inigo);
					messageService.postSpeech(context, null, inigo, "OK Let's go to the jail !");
					messageService.postSpeech(context, null, olukun, "Huh ... wait a minute ...");
					
					{
						List<Scene> scenes = dao.asListOfScenes(null, dao.queryScene(campaign.getKey()), null);
						if(scenes != null) {
							for(Scene seq : scenes) {
								System.err.println(seq.getEntity());
								final List<Message> messages = 
									dao.asListOfMessages(null, 
										dao.queryMessage(seq.getKey()), null, 
										Message.Properties.TIMESTAMP);
								if(messages != null) {
									for(Message msg : messages) {
										System.err.println(msg.getEntity());
									}
								}
							}
						}
					}
					
					{
						System.err.println("----------- Inigo messages");
						final Context context2 = new Context(romain);
						final List<SceneSDO> scenes = messageService.getMessages(context2, 
								campaign.getKey().getId(), 
								inigo.getKey().getId(), null, null);
						
						if(scenes != null) {
							for(SceneSDO sdo : scenes) {
								final Scene seq = sdo.getScene();
								System.err.println(seq.getEntity());
								final List<Message> messages = sdo.getMessages();
								if(messages != null) {
									for(Message msg : messages) {
										System.err.println(msg.getEntity());
									}
								}
							}
						}
					}

					{
						System.err.println("----------- Ulrich messages");
						final Context context2 = new Context(xavier);
						final List<SceneSDO> scenes = messageService.getMessages(context2, 
								campaign.getKey().getId(), 
								ulrich.getKey().getId(), null, null);
						
						if(scenes != null) {
							for(SceneSDO sdo : scenes) {
								final Scene seq = sdo.getScene();
								System.err.println(seq.getEntity());
								final List<Message> messages = sdo.getMessages();
								if(messages != null) {
									for(Message msg : messages) {
										System.err.println(msg.getEntity());
									}
								}
							}
						}
					}
					
					{
						System.err.println("----------- Olukun messages");
						final Context context2 = new Context(arnaud);
						final List<SceneSDO> scenes = messageService.getMessages(context2, 
								campaign.getKey().getId(), 
								olukun.getKey().getId(), null, null);
						
						if(scenes != null) {
							for(SceneSDO sdo : scenes) {
								final Scene seq = sdo.getScene();
								System.err.println(seq.getEntity());
								final List<Message> messages = sdo.getMessages();
								if(messages != null) {
									for(Message msg : messages) {
										System.err.println(msg.getEntity());
									}
								}
							}
						}
					}

					{
						System.err.println("----------- Hektor messages");
						final Context context2 = new Context(daniel);
						final List<SceneSDO> scenes = messageService.getMessages(context2, 
								campaign.getKey().getId(), 
								hektor.getKey().getId(), null, null);
						
						if(scenes != null) {
							for(SceneSDO sdo : scenes) {
								final Scene seq = sdo.getScene();
								System.err.println(seq.getEntity());
								final List<Message> messages = sdo.getMessages();
								if(messages != null) {
									for(Message msg : messages) {
										System.err.println(msg.getEntity());
									}
								}
							}
						}
					}

				} finally {
					if(tx.isActive()) {
						tx.rollback();
					}
				}
			}
			{
				final Transaction tx = datastore.beginTransaction();
				try {
					final Campaign campaign = campaignService.createCampaign(null, "another thomas' campaign", "Some game", "Some desc", null, thomas);
					campaign.setIcon("http://4.bp.blogspot.com/_SniTwfm5BwE/StS30qA7boI/AAAAAAAABpc/1kDwWjGglHI/s320/D%26D4E.jpg");
					createNotification(dao,  "this is another Notification", campaign.getKey());
					dao.save(null, campaign);
					tx.commit();
				} finally {
					if(tx.isActive()) {
						tx.rollback();
					}
				}
			}
			
			{
				final Transaction tx = datastore.beginTransaction();
				try {
					final Campaign campaign = campaignService.createCampaign(null, "Campaign 3", "Some game", "Some desc", null, daniel);
					campaign.setIcon("http://www.wizards.com/dnd/images/rhod_gallery/95863.jpg");
					createNotification(dao, "Please," + daniel.getNickname()+ " make OFF session to define your character", campaign.getKey());
					
					dao.save(null, campaign);
					tx.commit();
				} finally {
					if(tx.isActive()) {
						tx.rollback();
					}
				}
			}

			
			{
				final Transaction tx = datastore.beginTransaction();
				try {
					final Campaign campaign = campaignService.createCampaign(null, "Campaign 2", "Some game", "Some desc", null, daniel);
					campaign.setIcon("http://4.bp.blogspot.com/_SniTwfm5BwE/StS30qA7boI/AAAAAAAABpc/1kDwWjGglHI/s320/D%26D4E.jpg");
					createNotification(dao,  "this is another Notification", campaign.getKey());
					
					dao.save(null, campaign);
					tx.commit();
				} finally {
					if(tx.isActive()) {
						tx.rollback();
					}
				}
			}

			
			{
				final Transaction tx = datastore.beginTransaction();
				try {
					final Campaign campaign = campaignService.createCampaign(null, "Daniel's Campaign", "Some game", "Some desc", null, daniel);
					createNotification(dao,  "this is a Notification", campaign.getKey());
					final Data.Character joe = createCharacter(dao, campaign, "Joe", thomas);
					final Data.Character jack = createCharacter(dao, campaign, "Jack", arnaud);
					createNote(dao, jack, joe, "Why this guy is always following me ?!?");
					final Data.Character eric = createCharacter(dao, campaign, "Eric", null);
					tx.commit();
				} finally {
					if(tx.isActive()) {
						tx.rollback();
					}
				}
			}
		}

		
		/*
		 * Tests for Home
		 */
		{
			final Data.User user1 = createUser(dao, "user1@home.com", "User1");
			final Data.User user2 = createUser(dao, "user2@home.com", "User2");
			final Data.User user3 = createUser(dao, "user3@home.com", "User3");
			
			final Campaign campaign = campaignService.createCampaign(null, "My Home !", "Some game", "Some desc", null, user3);

			final Data.Character char1 = campaignService.createCharacter(null, campaign, "Char1", user1, null, null);
			final Data.Character char2 = campaignService.createCharacter(null, campaign, "Char2", user2, null, null);
			final Data.Character char3 = campaignService.createCharacter(null, campaign, "Char3", user3, null, null);
			
			Scene scene = messageService.startScene(context, "Intro", char1, char2, char3);
			messageService.postSpeech(context, null, char1, "Message 1");
			messageService.postSpeech(context, null, char2, "Message 2");
			messageService.postSpeech(context, null, char3, "Message 3");
		}
		

		/*
		 * Must be done out of TX because they are not attached to campaigns.
		 */
		for(Notification notification : notifications) {
			dao.save(null, notification);
		}
	}
}
